﻿using System;
using System.Data;
using System.IO;
using System.Linq;
using System.Net;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using Microsoft.SharePoint;
using PS.WebParts.Rollup.Custom.UI.WebControls.WebParts;
using Telerik.Web.UI;
using System.Web;
using System.Collections.Generic;

namespace PS.WebParts.Rollup.Custom.UI
{
    public partial class TelerikGridUserControl : UserControl
    {
        #region Event Handlers
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);

            documentsRadGrid.ColumnCreated += new GridColumnCreatedEventHandler(grid_ColumnCreated);

            documentsRadGrid.DataBound += grid_DataBound;

            documentsRadGrid.SortCommand += new GridSortCommandEventHandler(documentsRadGrid_SortCommand);

            RadMenu1.ItemClick += new RadMenuEventHandler(RadMenu1_ItemClick);
        }

        protected void RadGrid_NeedDataSource(object source, GridNeedDataSourceEventArgs e)
        {
            try
            {
                var grid = (RadGrid)source;

                GridGroupByExpression exp = null;

                if (PreSetGrouping.HasValue)
                {
                    grid.MasterTableView.GroupByExpressions.Clear();

                    exp = ConstructGroupByExpression(PreSetGrouping.Value.Key, PreSetGrouping.Value.Value);

                    grid.MasterTableView.GroupByExpressions.Add(exp);
                }

                DataBindGrid(grid, exp);
            }
            catch (Exception ex)
            {
            }
        }

        void documentsRadGrid_SortCommand(object source, GridSortCommandEventArgs e)
        {
            var grid = (RadGrid)source;

            DataBindGrid(grid, null);
        }

        void RadMenu1_ItemClick(object sender, RadMenuEventArgs e)
        {
            var header = e.Item.Text.Substring("Group By ".Length);

            SetGrouping(e.Item.Value, header);
        }

        protected void RadGrid1_GroupsChanging(object sender, GridGroupsChangingEventArgs e)
        {
            var grid = (RadGrid)sender;

            if (e.Action == GridGroupsChangingAction.Ungroup)
            {
                var c = grid.MasterTableView.GroupByExpressions.Count;

                if (c == 1) return;
            }

            var exp = e.Expression;

            DataBindGrid(grid, exp);

            grid.DataBind();
        }

        void grid_ColumnCreated(object sender, GridColumnCreatedEventArgs e)
        {
            if (e.Column.HeaderText.EndsWith(postFix))
                e.Column.Visible = false;
        }

        void grid_DataBound(object sender, EventArgs e)
        {
            var grid = (RadGrid)sender;

            foreach (GridColumn column in grid.MasterTableView.Columns)
            {
                if (column.HeaderText.EndsWith(postFix))
                {
                    column.Visible = false;
                }
                else
                {
                }
            }
        }

        #endregion

        #region Grid Helpers
        private void SetGrouping(string groupField, string alias)
        {
            documentsRadGrid.MasterTableView.GroupByExpressions.Clear();

            documentsRadGrid.MasterTableView.GroupByExpressions.Add(ConstructGroupByExpression(groupField, alias));

            documentsRadGrid.Rebind();
        }

        private GridGroupByExpression ConstructGroupByExpression(string groupByKey, string alias)
        {
            var gridGroupByExpression = new GridGroupByExpression();

            var gridGroupByField = new GridGroupByField();
            gridGroupByField.FieldAlias = groupByKey;
            gridGroupByField.FieldName = groupByKey;
            gridGroupByField.FormatString = "{0:D}";
            gridGroupByField.HeaderValueSeparator = ": ";
            gridGroupByField.HeaderText = alias;// "Header";
            gridGroupByField.SortOrder = GridSortOrder.Ascending;

            gridGroupByExpression.GroupByFields.Add(gridGroupByField);
            gridGroupByExpression.SelectFields.Add(gridGroupByField);

            return gridGroupByExpression;
        }

        private void DataBindGrid(RadGrid grid, GridGroupByExpression exp)
        {
            var ds = RawData;

            var columnInfo = WebPart.GetColumnInfo(ds);

            columnInfo = (from c in columnInfo orderby c.Order select c).ToList();

            ds = this.SetColumnOrder(columnInfo, ds);

            GenerateColumns(grid, ds, columnInfo);

            ds = ExpandedDataSourec(grid, ds, exp);

            grid.DataMember = "Rows";

            grid.DataSource = ds;
        }

        private void GenerateColumns(RadGrid grid, DataSet dataSet, List<RollupColumnInfo> columnInfo)
        {
            RadMenu1.Items.Clear();

            #region Build Columns
            grid.AutoGenerateColumns = false;
            grid.Columns.Clear();
            grid.MasterTableView.Columns.Clear();

            var dic = new Dictionary<string, string>();

            //if ( !IsPostBack ) 
            foreach (RollupColumnInfo info in columnInfo)
            {
                #region Toolbar Mappings
                string cleanName = info.Name;

                if (info.Name.EndsWith(postFix, StringComparison.InvariantCultureIgnoreCase))
                {
                    cleanName = info.Name.Substring(0, info.Name.LastIndexOf(postFix));

                    if (dic.ContainsKey(cleanName)) dic[cleanName] = info.Name;
                    else dic.Add(cleanName, info.Name);
                }
                else
                {
                    if (!dic.ContainsKey(cleanName)) dic[cleanName] = info.Name;
                }
                #endregion

                #region Create Column

                if (info.ColType.Equals("Text", StringComparison.InvariantCultureIgnoreCase))
                {
                    var col = new GridBoundColumn();

                    grid.MasterTableView.Columns.Add(col);

                    col.DataField = info.Name;

                    col.DataFormatString = info.TextPattern;
                    col.GroupByExpression = string.Format("{0} Group By {0}", info.Name);
                    col.SortExpression = info.Name;
                    col.AllowSorting = true;
                    col.AllowFiltering = true;
                    col.UniqueName = info.Name;

                    //col.Groupable = PreSetGrouping.HasValue;

                    col.Visible = !bool.Parse(info.Hidden);

                    col.HeaderText = info.Header;
                }
                else
                {
                    var col = new Telerik.Web.UI.GridHyperLinkColumn();

                    grid.MasterTableView.Columns.Add(col);

                    List<string> selected = new List<string>();

                    foreach (var kv in info.LinkSources)
                    {
                        bool value = false;

                        if (bool.TryParse(kv.Value, out value) && value)
                            selected.Add(kv.Key);
                    }

                    col.DataNavigateUrlFields = selected.ToArray();
                    col.DataNavigateUrlFormatString = info.LinkPattern;

                    col.DataTextField = info.Name;
                    col.DataTextFormatString = info.TextPattern;

                    col.GroupByExpression = string.Format("{0} Group By {0}", info.Name);
                    col.SortExpression = info.Name;
                    col.AllowFiltering = true;
                    col.UniqueName = info.Name;

                    col.Visible = !bool.Parse(info.Hidden);

                    col.HeaderText = info.Header;

                }


                #endregion
            }
            #endregion

            #region Build Toolbar
            try
            {
                foreach (GridColumn col in grid.MasterTableView.Columns)
                {
                    if (col.Visible && !col.UniqueName.EndsWith(postFix))
                    {
                        bool isMulti = IsMultiValue(dataSet, col.UniqueName);

                        AddButton(dic[col.UniqueName], "Group by " + col.HeaderText, isMulti);
                    }
                }
            }
            catch
            {

            }
            #endregion
        }

        #endregion

        private void AddButton(string fieldName, string fieldDesc, bool multivalue)
        {
            RadMenuItem item = new RadMenuItem(fieldDesc);

            if (!fieldName.EndsWith(postFix) && multivalue)
            {
                var sub = new RadMenuItem(fieldDesc + " " + flatFlag) {Value = fieldName + postFix};

                item.Items.Add(sub);
            }

            item.Value = fieldName;

            RadMenu1.Items.Add(item);
        }

        #region Properties
        public WebControls.WebParts.TelerikGridWebPart WebPart { get; set; }
        private KeyValuePair<string, string>? PreSetGrouping = new KeyValuePair<string, string>?();
        private string flatFlag = "(Flat)";
        private string postFix = "_flat";

        private DataSet _rawData = null;

        DataSet RawData
        {
            get
            {
                if (_rawData == null)
                    _rawData = WebPart.GetRawData();
                return _rawData;
            }
        }

        #endregion

        #region Data Manipulation
        DataSet SetColumnOrder(List<RollupColumnInfo> columnInfo, DataSet dataSet)
        {

            for (int i = 0; i < columnInfo.Count; i++)
            {
                dataSet.Tables[0].Columns[columnInfo[i].Name].SetOrdinal(i);
            }

            dataSet.AcceptChanges();

            return dataSet;
        }

        DataSet FlattenData(DataSet dataSet, List<string> groupByColumns)
        {
            var temp = dataSet.Copy();

            var table = temp.Tables[0];

            foreach (var groupByColumn in groupByColumns)
            {
                table.Columns.Add(groupByColumn + postFix);
            }

            var rows = new List<DataRow>();


            foreach (var groupByColumn in groupByColumns)
            {
                #region MyRegion
                rows.Clear();

                foreach (DataRow row in table.Rows)
                {
                    rows.Add(row);
                }
                #endregion
                foreach (DataRow row in rows)
                {
                    if (row.RowState == DataRowState.Deleted || row.RowState == DataRowState.Detached) continue;

                    if (row.IsNull(groupByColumn))
                    {
                        //temp.Tables[0].LoadDataRow(row.ItemArray, true);
                    }
                    else
                    {
                        var multiValues = ParseLookupFieldValue(row[groupByColumn]);

                        if (multiValues.Count == 1)
                        {
                            //temp.Tables[0].LoadDataRow(row.ItemArray, true);
                            row[groupByColumn + postFix] = multiValues[0];
                        }
                        else
                        {
                            foreach (var value in multiValues)
                            {
                                var newRow = table.LoadDataRow(row.ItemArray, true);

                                newRow[groupByColumn + postFix] = value;

                                newRow.AcceptChanges();
                            }
                            row.Delete();
                        }
                    }
                }
            }
            temp.AcceptChanges();

            temp = CleanLookups(temp);

            return temp;
        }

        private DataSet CleanLookups(DataSet set)
        {
            foreach (DataTable table in set.Tables)
            {
                var columnNames = new List<string>();

                foreach (DataColumn column in table.Columns)
                {
                    columnNames.Add(column.ColumnName);
                }

                foreach (DataRow row in table.Rows)
                {
                    foreach (var groupByColumn in columnNames)
                    {
                        if (row.IsNull(groupByColumn)) continue;

                        var rawValue = row[groupByColumn].ToString();

                        if (rawValue.Contains(";#"))
                        {
                            var texts = ParseLookupFieldValue(rawValue);

                            var cleanValue = string.Empty;

                            texts.ForEach(t => cleanValue += ", " + t);

                            row[groupByColumn] = cleanValue.Replace(";#", ", ").Trim(new char[] { ',', ' ' });
                        }
                    }
                }
            }

            set.AcceptChanges();

            return set;
        }

        List<string> GetMultiValueGroupColumns(DataSet ds, List<string> multiValueGroupColumns, GridGroupByExpression e)
        {
            for (int i = 0; i < e.GroupByFields.Count; i++)
            {
                var field = e.GroupByFields[i];

                string groupField = field.FieldName;

                if (groupField.EndsWith(postFix))
                {
                    groupField = groupField.Substring(0, groupField.LastIndexOf(postFix));

                    if (IsMultiValue(ds, groupField) && !multiValueGroupColumns.Contains(groupField))
                    {
                        multiValueGroupColumns.Add(groupField);
                    }
                }
            }

            return multiValueGroupColumns;
        }

        DataSet ExpandedDataSourec(RadGrid grid, DataSet ds, GridGroupByExpression exp)
        {

            var multiValueGroupColumns = new List<string>();

            for (int k = 0; k < grid.MasterTableView.GroupByExpressions.Count; k++)
            {
                multiValueGroupColumns = GetMultiValueGroupColumns(ds, multiValueGroupColumns, grid.MasterTableView.GroupByExpressions[k]);
            }

            if (exp != null)
            {
                multiValueGroupColumns = GetMultiValueGroupColumns(ds, multiValueGroupColumns, exp);

                for (int i = 0; i < exp.GroupByFields.Count; i++)
                {
                    var fieldName = exp.GroupByFields[i].FieldName;

                    if (!exp.GroupByFields[i].FieldName.EndsWith(postFix) && multiValueGroupColumns.Contains(fieldName))
                    {
                        exp.GroupByFields[i].FieldAlias += postFix;
                        exp.GroupByFields[i].FieldName += postFix;
                        exp.GroupByFields[i].HeaderText += exp.GroupByFields[i].FieldAlias + " " + flatFlag;

                        exp.SelectFields[i].FieldName += postFix;
                        exp.SelectFields[i].FieldAlias += postFix;

                        exp.SelectFields[i].HeaderText += exp.GroupByFields[i].FieldAlias + " " + flatFlag;
                    }
                }
            }

            ds = FlattenData(ds, multiValueGroupColumns);

            return ds;
        }

        private bool IsMultiValue(DataSet ds, string groupByColumn)
        {
            foreach (DataRow row in ds.Tables[0].Rows)
            {
                if (row.IsNull(groupByColumn))
                {
                    //temp.Tables[0].LoadDataRow(row.ItemArray, true);
                }
                else
                {
                    var multiValues = row[groupByColumn].ToString();

                    if (multiValues.Contains(";#")) return true;
                }
            }

            return false;
        }

        internal List<string> ParseLookupFieldValue(object input)
        {
            var list = new List<string>();

            try
            {
                var rawValue = input.ToString();

                var values = new SPFieldLookupValueCollection(rawValue);

                if (values.Count == 0)
                {
                    var values1 = new SPFieldMultiChoiceValue(rawValue);

                    for (int i = 0; i < values1.Count; i++)
                    {
                        var cleanValue = values1[i].Trim();

                        if (!String.IsNullOrEmpty(cleanValue))
                            list.Add(values1[i]);
                    }
                }
                else
                {
                    foreach (var value in values)
                    {
                        if (value == null) continue;

                        var cleanValue = value.ToString().Trim();

                        if (!String.IsNullOrEmpty(cleanValue))
                            list.Add(value.LookupValue);
                    }
                }
            }
            catch (Exception ex)
            {
            }

            return list;
        }
        #endregion

        internal void SetGridSkin(string p)
        {
            this.documentsRadGrid.Skin = p;
            this.RadMenu1.Skin = p;
        }

        internal void SetMenuVisible(bool value)
        {
            this.RadMenu1.Visible = value;

            documentsRadGrid.ShowGroupPanel = value;
        }

        internal void SetPageSize(int value)
        {
            if (value < 1) documentsRadGrid.AllowPaging = false;
            else
            {
                documentsRadGrid.AllowPaging = true;

                documentsRadGrid.PageSize = value;

            }
        }

        internal void SetPresetGrouping(string groupField, bool clearOnEmpty)
        {
            var ds = RawData;

            var columnInfo = WebPart.GetColumnInfo(ds);

            bool clear = false;

            if (!String.IsNullOrEmpty(groupField))
            {
                clearOnEmpty = false;

                var column = (from c in columnInfo where c.Name == groupField select c).FirstOrDefault();

                if (column != null)
                {
                    PreSetGrouping = new KeyValuePair<string, string>(column.Name, column.Header);

                    documentsRadGrid.ShowGroupPanel = false;

                    RadMenu1.Visible = false;
                }
                else clear = true;
            }
            else
            {
                clear = true;
            }

            if (clearOnEmpty || clear)
            {
                documentsRadGrid.GroupingEnabled = true;

                documentsRadGrid.ShowGroupPanel = true;

                // This is not necessary but we are explicitly removing the grouping so the admin will see that the 
                // Preset grouping is gone. By default the telerik grid remembers groupings.
                // Eventhough the preset grouping is gone, it looks like it doesn't work because the current grouping selection remains
                //documentsRadGrid.MasterTableView.GroupByExpressions.Clear();

                RadMenu1.Visible = true;
            }
        }

        internal void Reload()
        {
            documentsRadGrid.DataSource = null;

            documentsRadGrid.Rebind();
        }
    }
}
